#include "action_msg.h"
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h> 
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include "../data_proc/board_data_proc.h"

int g_msg_id_to_lua;
int g_msg_id_to_act;


#define HASH_SIZE_ELE_STATUS 21 

typedef struct _hash_status_table
{
    eleActCheck*  eleStatusArr[HASH_SIZE_ELE_STATUS];

}hash_status_table;

pthread_mutex_t mutex_hash;

pthread_mutex_t mutex_checkdata;

hash_status_table g_eleStatusStore;

int initHashEleStatus(void)
{
    memset(&g_eleStatusStore,0,sizeof(hash_status_table));
}

void freeHashEleStatus(void)
{
    int hashIndex = 0;
    eleActCheck * ptrCheckData = NULL;
    eleActCheck * ptrCheckDataPre = NULL;
    for(hashIndex=0;hashIndex<HASH_SIZE_ELE_STATUS;hashIndex++)
    {
        ptrCheckData = g_eleStatusStore.eleStatusArr[hashIndex];
        while(ptrCheckData)
        {
            ptrCheckDataPre = ptrCheckData;
            ptrCheckData=ptrCheckData->next;
            free(ptrCheckDataPre);
            ptrCheckDataPre = NULL;
        }
    }
}

int getHashCode(int idIn)
{
    int ret = idIn%20 + 1;
    return ret;
}


int registerCheckData(eleActCheck * checkDataIn)
{

    int sid = checkDataIn->valueDesired.sid;
    int hashCode = getHashCode(sid);
    int retRegSuccess = 1;

    eleActCheck * ptrCheckDataInHashTable = g_eleStatusStore.eleStatusArr[hashCode];

    //printf("enter in registerCheckData, sid[%d],type[%d]\n",sid,checkDataIn->valueDesired.frameType);
    if(ptrCheckDataInHashTable==NULL)
    {
        printf("registerCheckData, node is null, malloc here\n");
        pthread_mutex_lock(&mutex_hash);   
        g_eleStatusStore.eleStatusArr[hashCode] = (eleActCheck *)malloc(sizeof(eleActCheck));
        memcpy(g_eleStatusStore.eleStatusArr[hashCode],checkDataIn,sizeof(eleActCheck));
        g_eleStatusStore.eleStatusArr[hashCode]->next = NULL;
        pthread_mutex_unlock(&mutex_hash);
    }
    else {

        //find the node with sid == checkDataIn->valueDesired.sid
        eleActCheck * ptrPre = ptrCheckDataInHashTable;
        while(ptrCheckDataInHashTable)
        {
            if(ptrCheckDataInHashTable->valueDesired.sid == sid)
            {
                break;
            }
            ptrPre = ptrCheckDataInHashTable;
            ptrCheckDataInHashTable = ptrCheckDataInHashTable->next;

        }

        pthread_mutex_lock(&mutex_hash);
        if(ptrCheckDataInHashTable == NULL)
        {//not find
            printf("registerCheckData, node not find, malloc here\n");
            ptrCheckDataInHashTable = (eleActCheck *)malloc(sizeof(eleActCheck));
            memcpy(ptrCheckDataInHashTable,checkDataIn,sizeof(eleActCheck));
            ptrCheckDataInHashTable->next = NULL;
            ptrPre->next = ptrCheckDataInHashTable;
        }
        else
        {//find
            if(LUA_ACT_WAITING == ptrCheckDataInHashTable->status)
            {
                retRegSuccess = 0;
            }
            ptrCheckDataInHashTable->status = checkDataIn->status ;
            ptrCheckDataInHashTable->valueDesired.sid =  checkDataIn->valueDesired.sid;
            ptrCheckDataInHashTable->valueDesired.frameType =  checkDataIn->valueDesired.frameType;        
            //memcpy(ptrCheckDataInHashTable,checkDataIn,sizeof(eleActCheck));
        }
        pthread_mutex_unlock(&mutex_hash);
    }
    return  retRegSuccess;
}

eleActCheck * findDataInTable(int sidIn)
{
    int sid = sidIn;
    int hashCode = getHashCode(sid);

    eleActCheck * ptrCheckDataInHashTable = g_eleStatusStore.eleStatusArr[hashCode];

    while(ptrCheckDataInHashTable)
    {
        if(ptrCheckDataInHashTable->valueDesired.sid == sid)
        {
            break;
        }
        ptrCheckDataInHashTable = ptrCheckDataInHashTable->next;

    }

    return ptrCheckDataInHashTable;

}

int updateData(void * dataIn)
{
    recvDataEleCtl * ptrData = (recvDataEleCtl *)dataIn;
    eleActCheck * ptrDataInTable = findDataInTable(ptrData->sid);
    printf("in updateData, sid[%d],type[%d]\n",ptrData->sid,ptrData->frameType);
    if(ptrDataInTable)
    {
        pthread_mutex_lock(&mutex_hash);
        if(ptrDataInTable->valueDesired.frameType == ptrData->frameType)
        {
            ptrDataInTable->status = LUA_ACT_FINISHED;
        }
        else if(ptrDataInTable->valueDesired.frameType==CHECK_ACT_ERROR)
        {
            ptrDataInTable->valueDesired.frameType = LUA_ACT_ERROR;
        }
        pthread_mutex_unlock(&mutex_hash);
    }
    else 
    {
        printf("in updateData, find node with sid[%d] failed\n",ptrData->sid);
        
        int hashCode = getHashCode(ptrData->sid);

        eleActCheck * ptrCheckDataInHashTable = g_eleStatusStore.eleStatusArr[hashCode];
        int i = 0;
        while(ptrCheckDataInHashTable)
        {
            printf("sid in node:%d,i=%d\n",ptrCheckDataInHashTable->valueDesired.sid,i++);
            ptrCheckDataInHashTable = ptrCheckDataInHashTable->next;

        }
    }
}

int checkAllFinished(void * dataIn)
{
    eleActCheck * desiredData = (eleActCheck *)dataIn;

    int allFinished = 1;

    eleActCheck * dataPtrInTable = NULL;
    while(desiredData)
    {
        dataPtrInTable = findDataInTable(desiredData->valueDesired.sid);
        if(dataPtrInTable==NULL)
        {
           allFinished = 0;
           break; 
        }

        if(dataPtrInTable->status != LUA_ACT_FINISHED)
        {
           allFinished = 0;
           break;
        }
        desiredData = desiredData->next;
    }

    return allFinished;
}

void refreshStatus(void * dataIn)
{
    eleActCheck * desiredData = (eleActCheck *)dataIn;

    eleActCheck * dataPtrInTable = NULL;
    while(desiredData)
    {
        dataPtrInTable = findDataInTable(desiredData->valueDesired.sid);

        if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
        {

            printf("sid %d ,status:%d\n",desiredData->valueDesired.sid,dataPtrInTable->status);
            dataPtrInTable->status = LUA_ACT_TIMEOUT;
        }
        desiredData = desiredData->next;
    }
}

int checkAllReady(void * dataIn, int num)
{
    move_param * pstMoveParam = (move_param *)dataIn;

    int allReady = 1;
    int numTmp = 0;

    eleActCheck * dataPtrInTable = NULL;
    while(numTmp < num)
    {
        dataPtrInTable = findDataInTable(pstMoveParam->sid);

        if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
        {
           allReady = 0;
           break;
        }
        pstMoveParam ++;
        numTmp ++ ;
    }

    return allReady;
}

void set_check_data(move_param * paramIn, int num, void ** dataOut)
{
    //printf("enter in set_check_data\n");
    if(paramIn==NULL)
    {
        *dataOut = NULL;
        return;
    }    
    pthread_mutex_lock(&mutex_checkdata);
    eleActCheck * checkData = (eleActCheck *)malloc(sizeof(eleActCheck)*num);
    pthread_mutex_unlock(&mutex_checkdata);
    memset(checkData,0,sizeof(eleActCheck)*num);

    eleActCheck * ptrCheckData = checkData;
    //int regResult = 0;
    for(int i=0;i<num;i++)
    {
        ptrCheckData->valueDesired.sid = paramIn[i].sid;

        if(paramIn[i].sid>=84 && paramIn[i].sid <= 87)
        {
            //for pump and valves of dj
            ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;
        }
        else if(paramIn[i].sid>=100 && paramIn[i].sid <= 105)
        {
            //for wantec ele controller
            ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;
        }
        else if(paramIn[i].sid == 1)
        {
            ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;
        }
        else if(paramIn[i].sid == 255)
        {//proc the exception
            ptrCheckData->status = LUA_ACT_FINISHED;
            continue;
        }
        else
        {
            if(paramIn[i].pos == 0)
            {
                ptrCheckData->valueDesired.frameType = CHECK_RET_BACK_END;
            }
            else
            {
                ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;
            }
        }     

        if(i<(num-1))
        {
            ptrCheckData->next = ptrCheckData+1;
        }
        registerCheckData(ptrCheckData);
        ptrCheckData++;      
    }

    // ptrCheckData = checkData;
    // for(int i1=0;i1<num;i1++)
    // {
    //     printf("check sid:%d, type:%d\n",ptrCheckData->valueDesired.sid,ptrCheckData->valueDesired.frameType);
    //     ptrCheckData++;
    // }
    *dataOut = checkData;
}

int update(void * dataIn,void * stdData)
{
    recvDataEleCtl * ptrData = (recvDataEleCtl *)dataIn;
    eleActCheck * dataDesired = (eleActCheck *)stdData;
    eleActCheck * ptrDataDesired = dataDesired;

    
    int ret = 1;
    if(dataIn==NULL || stdData==NULL)
    {
        return 0;
    }
    printf("int update, sid:%d,ptrData.frameType:%d\n",ptrData->sid, ptrData->frameType);
    while(ptrDataDesired!=NULL)
    {
        if( ptrDataDesired->valueDesired.sid != ptrData->sid)
        {
            if(ptrDataDesired->status == 0)
            {
               //printf("check_update set ret to 0,111\n");
               ret = 0;
            }            
        }
        else //if(ptrDataDesired->valueDesired.sid == ptrData->sid)
        {
            if(ptrDataDesired->valueDesired.frameType == ptrData->frameType)
            {
               //printf("check_update set status to 1, sid[%d]\n",ptrData->sid);
               ptrDataDesired->status = 1;
            }
            
            if(ptrDataDesired->status == 0)
            {
                //printf("check_update set ret to 0,222\n");
                ret = 0;
            }
        }
        ptrDataDesired=ptrDataDesired->next;
    }
    //printf("check_update ret:%d\n",ret);
    return ret;
}

int isAllFinished(void * dataIn)
{
    //recvDataEleCtl * ptrData = (recvDataEleCtl *)dataIn;
    eleActCheck * dataDesired = (eleActCheck *)dataIn;
    eleActCheck * ptrDataDesired = dataDesired;

    
    int ret = 1;
    if(dataIn==NULL)
    {
        return 0;
    }
    while(ptrDataDesired!=NULL)
    {
        if(ptrDataDesired->status == 0)
        {
            //printf("check_update set ret to 0,222\n");
            ret = 0;
            break;
        }
        ptrDataDesired=ptrDataDesired->next;
    }
    //printf("check_update ret:%d\n",ret);
    return ret;
}

int g_flag_exit_thread = 0;
int g_msg_id_lua = -1;

int uimMoveAct(move_param * paramIn, int num, int timeOut_mm)
{

  key_t key = ftok(msgQueueKeyPath, 0x1234);
  if(key < 0)
  {
      perror("ftok");
      return -1;
  }
//this msg id is used to send to act
  int msg_id = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
  if(msg_id < 0)
  {
      perror("msgget");
      return -1;
  }

  msg_ctl_uim msgToAct;

  memset(&msgToAct,0,sizeof(msg_ctl_uim));

  msgToAct.type = QUEUE_MSG_TYPE_UIM;

  

  key = ftok(msgLuaQueuePath, keyMsg_LUA);
  if(key < 0)
  {
      perror("ftok");
      return -1;
  }
  //this msg id is used to recv the ack
  g_msg_id_lua = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
  if(g_msg_id_lua < 0)
  {
      perror("msgget");
      return -1;
  }

  //printf("g_msg_id_lua is %d\n",g_msg_id_lua);

   char * ptrCheckData = NULL;
   set_check_data(paramIn, num, (void**)&ptrCheckData);

   if(ptrCheckData==NULL)
   {
       printf("set check data failed\n");
       return -2;
   }
 
   pthread_t appAckRecvHandl = 0;
   lua_thread_param stThreadParam;
   memset(&stThreadParam,0,sizeof(lua_thread_param));
   stThreadParam.msg_id = g_msg_id_lua;
   stThreadParam.numAct = num;
   stThreadParam.pstCheckData = (eleActCheck*)ptrCheckData;

   g_flag_exit_thread = 0;
   pthread_create(&appAckRecvHandl,NULL,thread_recv_msg,&stThreadParam);

   move_param * ptrMoveParam =  paramIn;
   #define LUA_MOVE 1
   int sendOkFlag = 1;
    for(int i=0;i<num;i++)
    {
        msgToAct.ctlFrame.sid = ptrMoveParam->sid;
        msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;
        msgToAct.ctlFrame.opcode = LUA_MOVE;
        if(msgToAct.ctlFrame.sid >=80 && msgToAct.ctlFrame.sid <=83)
        {
            msgToAct.type = QUEUE_MSG_TYPE_BOARDS; 
            msgToAct.ctlFrame.sid = 1;
            
            msgToAct.ctlFrame.un_cmd.moveCtl.ele_index = ptrMoveParam->sid - 80;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            //printf("ele_index:%d,pos:%d\n",msgToAct.ctlFrame.un_cmd.moveCtl.ele_index,
            //msgToAct.ctlFrame.un_cmd.moveCtl.position);
        }
        else if(msgToAct.ctlFrame.sid >=10 && msgToAct.ctlFrame.sid <=60)
        {
            msgToAct.type = QUEUE_MSG_TYPE_UIM;            
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        }
        
        if(msgsnd(msg_id, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
        {
            printf("msgsnd failed, when i=%d\n",i);
            perror("msgsnd");
            sendOkFlag = 0;
        }
        ptrMoveParam++;
    }
    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_mm;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = isAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

     

  g_flag_exit_thread = 1;
  //void * threadRet = NULL;
  pthread_join(appAckRecvHandl,NULL);

  //printf("msg recv thread exit\n"); 
//   if(threadRet)
//   {
//     free(threadRet);
//     threadRet = NULL;
//   }

//  printf("threadRet free finished\n");
    //printf("ptrCheckData free now\n");
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");

  return flagSuccess;
}

int uimMoveAct_multi(move_param * paramIn, int num, int timeOut_ms)
{

  msg_ctl_uim msgToAct;

  memset(&msgToAct,0,sizeof(msg_ctl_uim));

  msgToAct.type = QUEUE_MSG_TYPE_UIM;

   int isAllReady = checkAllReady(paramIn, num);

   if(!isAllReady)
   {
       printf("not all ready\n");
       return 3;
   }

   char * ptrCheckData = NULL;
   set_check_data(paramIn, num, (void**)&ptrCheckData);

   if(ptrCheckData==NULL)
   {
       printf("set check data failed\n");
       return 2;
   }   

   move_param * ptrMoveParam =  paramIn;
   #define LUA_MOVE 1
   int sendOkFlag = 1;
    for(int i=0;i<num;i++)
    {
        msgToAct.ctlFrame.sid = ptrMoveParam->sid;
        msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;
        msgToAct.ctlFrame.opcode = LUA_MOVE;
        if(msgToAct.ctlFrame.sid >=80 && msgToAct.ctlFrame.sid <=83)
        {
            msgToAct.type = QUEUE_MSG_TYPE_BOARDS; 
            msgToAct.ctlFrame.sid = 1;
            
            msgToAct.ctlFrame.un_cmd.moveCtl.ele_index = ptrMoveParam->sid - 80;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            //printf("ele_index:%d,pos:%d\n",msgToAct.ctlFrame.un_cmd.moveCtl.ele_index,
            //msgToAct.ctlFrame.un_cmd.moveCtl.position);
        }
        else if(msgToAct.ctlFrame.sid >=10 && msgToAct.ctlFrame.sid <=60)
        {
            msgToAct.type = QUEUE_MSG_TYPE_UIM;
            if(ptrMoveParam->pos == 0)
            {
                msgToAct.ctlFrame.opcode = UIM_GOZERO;
            }            
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        }
        else if(msgToAct.ctlFrame.sid == 1)
        {//for adp z move
            msgToAct.type = QUEUE_MSG_TYPE_UIM; 
            msgToAct.ctlFrame.opcode = TECAN_Z_MOVE;           
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        }
        
        if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
        {
            printf("msgsnd failed, when i=%d\n",i);
            perror("msgsnd");
            sendOkFlag = 0;
        }
        ptrMoveParam++;
    }
    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_ms;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    if(!flagSuccess)
    {
        refreshStatus(ptrCheckData);//if status is waiting, set it to be timeout
    }
    //printf("ptrCheckData free now\n");
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");

  return flagSuccess;
}

int uimInitAct_multi(move_param * paramIn, int num, int timeOut_ms)
{

  msg_ctl_uim msgToAct;

  memset(&msgToAct,0,sizeof(msg_ctl_uim));

  msgToAct.type = QUEUE_MSG_TYPE_UIM;

   int isAllReady = checkAllReady(paramIn, num);

   if(!isAllReady)
   {
       printf("not all ready\n");
       return 3;
   }

   char * ptrCheckData = NULL;
   set_check_data(paramIn, num, (void**)&ptrCheckData);

   if(ptrCheckData==NULL)
   {
       printf("set check data failed\n");
       return 2;
   }   

   move_param * ptrMoveParam =  paramIn;

   int sendOkFlag = 1;
    for(int i=0;i<num;i++)
    {
        msgToAct.ctlFrame.sid = ptrMoveParam->sid;
        msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;
        msgToAct.ctlFrame.opcode = UIM_MOTOR_INIT;
        if(msgToAct.ctlFrame.sid >=80 && msgToAct.ctlFrame.sid <=83)
        {
            msgToAct.type = QUEUE_MSG_TYPE_BOARDS; 
            msgToAct.ctlFrame.sid = 1;
            msgToAct.ctlFrame.opcode = RET_BACK;
            msgToAct.ctlFrame.un_cmd.moveCtl.ele_index = ptrMoveParam->sid - 80;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            //printf("ele_index:%d,pos:%d\n",msgToAct.ctlFrame.un_cmd.moveCtl.ele_index,
            //msgToAct.ctlFrame.un_cmd.moveCtl.position);
        }
        else if(msgToAct.ctlFrame.sid >=10 && msgToAct.ctlFrame.sid <=60)
        {
            msgToAct.type = QUEUE_MSG_TYPE_UIM;            
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        }
        else if(msgToAct.ctlFrame.sid == 1)
        {//for adp z move
            msgToAct.type = QUEUE_MSG_TYPE_UIM; 
            msgToAct.ctlFrame.opcode = TECAN_Z_MOVE;           
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = 0;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        }
        
        if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
        {
            printf("msgsnd failed, when i=%d\n",i);
            perror("msgsnd");
            sendOkFlag = 0;
        }
        ptrMoveParam++;
    }
    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_ms;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    if(!flagSuccess)
    {
        refreshStatus(ptrCheckData);//if status is waiting, set it to be timeout
    }
    //printf("ptrCheckData free now\n");
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
        printf("ptrCheckData free finished\n");    
  //printf("ptrCheckData free finished\n");

  return flagSuccess;
}

int adpCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_mm)
{

    #define SID_ADP 1
    msg_ctl_uim msgToAct;
  
    int isAdpReady = 1;
    eleActCheck * dataPtrInTable = findDataInTable(SID_ADP);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isAdpReady = 0;
        printf("in adpCtl.ADP is busy!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_UIM;
    msgToAct.ctlFrame.sid = SID_ADP;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = SID_ADP;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);
   
    int sendOkFlag = 1;
    int isValid = 0; 

    switch (opcodeIn)
    {
      case TECAN_LOAD_TIP:
      case TECAN_DROP_TIP:
      {
        //TecanTipParam * ptrTipParam = (TecanTipParam *)paramIn;

        tecan_tip_param * ptrParam = &(msgToAct.ctlFrame.un_cmd.tecanCtlData.tipParam);
        memcpy(ptrParam,paramIn,sizeof(tecan_tip_param));
        isValid = 1;
      }
      break;
      case TECAN_SUCK:
      case TECAN_SPIT:
      case TECAN_SPIT_SIMPLE:
      {
        //TecanLiquidParam * ptrLiquidParam = (TecanLiquidParam *)paramIn;

        tecan_liquid_param * ptrParam = &(msgToAct.ctlFrame.un_cmd.tecanCtlData.liquidParam);
        memcpy(ptrParam,paramIn,sizeof(tecan_liquid_param));
        isValid = 1;
      }
      break;

      case TECAN_Z_MOVE:
      {
        move_param * ptrMoveParam = (move_param *)paramIn;
        msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
        msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
        msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
        msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
        isValid = 1;
      }
      break;
      case TECAN_SUCK_EXT:
      case TECAN_SUCK_P:
      case TECAN_SUCK_SIMPLE:
      {
        suck_param * ptrSuckParamSrc = (suck_param *)paramIn;
        suck_param * ptrSuckParamDst = (suck_param *)(&msgToAct.ctlFrame.un_cmd.suckParam);
        memcpy(ptrSuckParamDst,ptrSuckParamSrc,sizeof(suck_param));
        // msgFrame.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->acc();
        // msgFrame.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec();
        // msgFrame.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->position();
        isValid = 1;
      }
      break;
      case TECAN_INIT:
      {
        tecan_init_param * ptrInitParam = (tecan_init_param *)paramIn;
        msgToAct.ctlFrame.un_cmd.tecanCtlData.initParam.detectType = ptrInitParam->detectType;
        isValid = 1;
      }
      break;
      case TECAN_RESET:
      {
        //tecan_init_param * ptrInitParam = (tecan_init_param *)paramIn;
        //msgToAct.ctlFrame.un_cmd.tecanCtlData.initParam.detectType = ptrInitParam->detectType;
        isValid = 1;
      }
      break;
      default:
      break;
    }
  
    if(isValid==0)
    {
pthread_mutex_lock(&mutex_checkdata);
        if(ptrCheckData)
        {
            free(ptrCheckData);
            ptrCheckData = NULL;
        }
pthread_mutex_unlock(&mutex_checkdata);
        return -1;
    } 
      
    if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
    {
        printf("adpCtl,msgsnd failed\n");
        perror("msgsnd");
        sendOkFlag = 0;
    }

    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_mm;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    dataPtrInTable = findDataInTable(SID_ADP);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        dataPtrInTable->status = LUA_ACT_TIMEOUT;
        printf("in adpCtl.ADP is busy!\n");
    }
    //printf("ptrCheckData free now\n");
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");

    return flagSuccess;
}

int ScancodeCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_mm)
{
    #define SID_SCANCODE (SUBBOARD_BASE+(SCANCODE_BOARD<<5))
    msg_ctl_uim msgToAct;
  
    int isScanCodeReady = 1;

    const scancode_param * pstScanCodeParam = (const scancode_param *)paramIn;
    int chanId = pstScanCodeParam->chanNum;
    int sidScancode = SID_SCANCODE + chanId;
    eleActCheck * dataPtrInTable = findDataInTable(sidScancode);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isScanCodeReady = 0;
        printf("in ScancodeCtl, scancode is busy!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = SCANCODE_BOARD;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidScancode;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);
   
    int sendOkFlag = 1;
    int isValid = 0;

    switch (opcodeIn) 
    {
        case SCANCODE_CTL:
        {
            memcpy(&(msgToAct.ctlFrame.un_cmd.scancodeParam) ,pstScanCodeParam,sizeof(scancode_param));
            isValid = 1;
        }
        break;

    }    
  
    if(isValid==0)
    {
        pthread_mutex_lock(&mutex_checkdata);
        if(ptrCheckData)
        {
            free(ptrCheckData);
            ptrCheckData = NULL;
        }
        pthread_mutex_unlock(&mutex_checkdata);
        return -1;
    } 
      
    if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
    {
        printf("scancode,msgsnd failed\n");
        perror("msgsnd");
        sendOkFlag = 0;
    }

    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_mm;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    dataPtrInTable = findDataInTable(sidScancode);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        dataPtrInTable->status = LUA_ACT_TIMEOUT;
        printf("in scancode.scancode is busy!\n");
    }
    //printf("ptrCheckData free now\n");
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");
    return flagSuccess;
}

int  djCleanCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_ms)
{
    #define SID_DJCTL (SUBBOARD_BASE+(IO_EXPAND_BOARD<<5))
    msg_ctl_uim msgToAct;
  
    int isCleanCtlReady = 1;

    const djLiquidCtl * pstDjCtlParam = (const djLiquidCtl *)paramIn;
    int chanId = pstDjCtlParam->chanNum;
    int sidDjClean = SID_DJCTL + chanId;
    eleActCheck * dataPtrInTable = findDataInTable(sidDjClean);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isCleanCtlReady = 0;
        printf("in djCleanCtl, scancode is busy!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = IO_EXPAND_BOARD;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidDjClean;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;
    printf("sidDjClean wait,%d\n",sidDjClean);
    registerCheckData(ptrCheckData);
   
    int sendOkFlag = 1; 

    memcpy(&(msgToAct.ctlFrame.un_cmd.djLiquidParam) ,pstDjCtlParam,sizeof(djLiquidCtl));

      
    if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
    {
        printf("djCleanCtl,msgsnd failed\n");
        perror("msgsnd");
        sendOkFlag = 0;
    }

    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_ms;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    dataPtrInTable = findDataInTable(sidDjClean);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        dataPtrInTable->status = LUA_ACT_TIMEOUT;
        printf("in djCleanCtl. djCleanCtl is busy!\n");
    }
    //printf("ptrCheckData free now\n");    
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");

    return flagSuccess;
}

int  drawerLockCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_ms)
{
    #define SID_DRAWERLOCK (SUBBOARD_BASE+(IO_EXPAND_BOARD<<5))
    msg_ctl_uim msgToAct;
  
    int isCleanCtlReady = 1;

    const drawer_lock_param * pstDrawerLockParam = (const drawer_lock_param *)paramIn;
    int chanId = pstDrawerLockParam->drawerId;
    int sidDrawerLock = SID_DRAWERLOCK + chanId + MAX_NUM_PV+1;
    eleActCheck * dataPtrInTable = findDataInTable(sidDrawerLock);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isCleanCtlReady = 0;
        printf("in drawerLockCtl, scancode is busy!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = IO_EXPAND_BOARD;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidDrawerLock;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);
   
    int sendOkFlag = 1; 

    memcpy(&(msgToAct.ctlFrame.un_cmd.drawerLockParam) ,pstDrawerLockParam,sizeof(drawer_lock_param));

      
    if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
    {
        printf("drawerLockCtl,msgsnd failed\n");
        perror("msgsnd");
        sendOkFlag = 0;
    }

    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeOut_ms;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    dataPtrInTable = findDataInTable(sidDrawerLock);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        dataPtrInTable->status = LUA_ACT_TIMEOUT;
        printf("in drawerLockCtl. %d is busy!\n",sidDrawerLock);
    }
    //printf("ptrCheckData free now\n");  
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finised\n");  

    return flagSuccess;
}


int  readTempCtl(const void * paramIn,int boardIdIn,unsigned int opcodeIn, int timeOut_ms)
{

    #define SID_TEMP_READ (SUBBOARD_BASE+(boardIdIn<<5))
    msg_ctl_uim msgToAct;
  
    int isCleanCtlReady = 1;

    const temp_read_param * pstTempReadParam = (const temp_read_param *)paramIn;
    int chanId = pstTempReadParam->chanNum;
    int sidReadTemp = SID_TEMP_READ + chanId + PURIFY_READ_TEMP_BASE;
    eleActCheck * dataPtrInTable = findDataInTable(sidReadTemp);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isCleanCtlReady = 0;
        printf("in readTempCtl,  is already runing!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = boardIdIn;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidReadTemp;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);

    memcpy(&(msgToAct.ctlFrame.un_cmd.tempReadParam) ,pstTempReadParam,sizeof(temp_read_param));

    int flagSuccess = sendSubboardMsgAndWaitResp(&msgToAct,ptrCheckData,sidReadTemp,timeOut_ms); 
    
    return flagSuccess;
}

int  shakeCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_ms)
{

    #define SID_SHAKE (SUBBOARD_BASE+(PURIFICATION_BOARD<<5))
    msg_ctl_uim msgToAct;
  
    int isShakeCtlReady = 1;

    const purifyCtl * pstShakeParam = (const purifyCtl *)paramIn;
    const heatParam * pstHeatCtlData = (const heatParam *)paramIn;
    int chanId = pstShakeParam->chanNum;
    int sidShakeCtl = SID_SHAKE + chanId + PURIFY_SHAKE_BASE;
    if(opcodeIn==HEAT_CTL)
    {
        chanId = pstHeatCtlData->chan;
        sidShakeCtl = SID_SHAKE + chanId + PURIFY_HEAT_BASE;
    }
    eleActCheck * dataPtrInTable = findDataInTable(sidShakeCtl);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isShakeCtlReady = 0;
        printf("in shakeCtl,  is already runing!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = PURIFICATION_BOARD;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidShakeCtl;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);

    if(opcodeIn == HEAT_CTL)
    {       
        memcpy(&(msgToAct.ctlFrame.un_cmd.heatCtlData) ,pstHeatCtlData,sizeof(heatParam)); 
    }
    else
    {
        memcpy(&(msgToAct.ctlFrame.un_cmd.purifyCtlData) ,pstShakeParam,sizeof(purifyCtl));
    }

    int flagSuccess = sendSubboardMsgAndWaitResp(&msgToAct,ptrCheckData,sidShakeCtl,timeOut_ms); 
    
    return flagSuccess;
}

int  sealCtl(const void * paramIn,unsigned int opcodeIn, int timeOut_ms)
{

    #define SID_SEAL (SUBBOARD_BASE+(THERMAL_SEAL_BOARD<<5))
    msg_ctl_uim msgToAct;
  
    int isSealCtlReady = 1;

    const heatParam * pstHeatCtlData = (const heatParam *)paramIn;
    int chanId = pstHeatCtlData->chan;
    int sidSealCtl = SID_SEAL + chanId;

    eleActCheck * dataPtrInTable = findDataInTable(sidSealCtl);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isSealCtlReady = 0;
        printf("in sealCtl,  is already runing!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = THERMAL_SEAL_BOARD;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));  

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidSealCtl;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);

    if(opcodeIn == HEAT_CTL)
    {       
        memcpy(&(msgToAct.ctlFrame.un_cmd.heatCtlData) ,pstHeatCtlData,sizeof(heatParam)); 
    }
    int flagSuccess = sendSubboardMsgAndWaitResp(&msgToAct,ptrCheckData,sidSealCtl,timeOut_ms); 
    
    return flagSuccess;
}

int  qpcrSubCtl(int qpcrId, const void * paramIn,unsigned int opcodeIn, int timeOut_ms)
{

    int boardId = qpcrId?QPCR_CTRL_BOARD_1:QPCR_CTRL_BOARD;
    #define SID_QPCR (SUBBOARD_BASE+(boardId<<5))
    msg_ctl_uim msgToAct;
  
    int isQpcrReady = 1;

    const qpcrCtl * pstQpcrParam = (const qpcrCtl *)paramIn;
    
    int chanId = pstQpcrParam->chanNum;    

    if(opcodeIn == HEAT_CTL)
    {
        const heatParam * pstHeatParam = (const heatParam *)paramIn;
        chanId = pstHeatParam->chan;
    }

    int sidQpcrCtl = SID_QPCR + chanId;

    eleActCheck * dataPtrInTable = findDataInTable(sidQpcrCtl);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        isQpcrReady = 0;
        printf("in shakeCtl,  is already runing!\n");
        return 2;
    }

    memset(&msgToAct,0,sizeof(msg_ctl_uim));

    msgToAct.type = QUEUE_MSG_TYPE_BOARDS;
    msgToAct.ctlFrame.sid = boardId;
    msgToAct.ctlFrame.opcode = opcodeIn;
    msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;

    if(opcodeIn == LIGHT_CTL)
    {
        memcpy(&msgToAct.ctlFrame.un_cmd.qpcrCtlData,pstQpcrParam,sizeof(qpcrCtl));
    }
    else if(opcodeIn == HEAT_CTL)
    {
        memcpy(&msgToAct.ctlFrame.un_cmd.heatCtlData,pstQpcrParam,sizeof(heatParam));        
    }


    eleActCheck * ptrCheckData = (eleActCheck*)malloc(sizeof(eleActCheck));
   

    if(ptrCheckData==NULL)
    {
       printf("set check data failed\n");
       return -2;
    }

    memset(ptrCheckData,0,sizeof(eleActCheck));
    ptrCheckData->status = LUA_ACT_WAITING;
    ptrCheckData->valueDesired.sid = sidQpcrCtl;
    ptrCheckData->valueDesired.frameType = CHECK_MOVE_END;

    registerCheckData(ptrCheckData);

    memcpy(&(msgToAct.ctlFrame.un_cmd.heatCtlData) ,pstQpcrParam,sizeof(qpcrCtl)); 

    int flagSuccess = sendSubboardMsgAndWaitResp(&msgToAct,ptrCheckData,sidQpcrCtl,timeOut_ms); 
    
    return flagSuccess;
}

int sendSubboardMsgAndWaitResp(void * msgIn,void * checkDataIn,int uniqueId, int timeout_ms)
{
    msg_ctl_uim * pstMsgToAct = (msg_ctl_uim *)msgIn;
    
    int sendOkFlag = 1; 

    if(msgsnd(g_msg_id_to_act, (void*)pstMsgToAct, sizeof(ctl_uim), 0) < 0)
    {
        printf("sendSubboardMsgAndWaitResp,msgsnd failed\n");
        perror("msgsnd");
        sendOkFlag = 0;
    }

    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_mm = timeout_ms;
        
        while(count_mm>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(checkDataIn);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_mm--;
            if(count_mm<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    eleActCheck * dataPtrInTable = findDataInTable(uniqueId);

    if(dataPtrInTable && dataPtrInTable->status == LUA_ACT_WAITING)
    {
        dataPtrInTable->status = LUA_ACT_TIMEOUT;
        printf("in readTempCtl. %d is busy!\n",uniqueId);
    }

    eleActCheck * ptrCheckData = (eleActCheck *)checkDataIn;
    //printf("ptrCheckData free now\n");  
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");  
    return flagSuccess;    
} 

void * thread_recv_msg(void * param)
{
   lua_thread_param * pstParam =  (lua_thread_param *)param;

   if(pstParam==NULL)
   {
      return NULL;
   }

   int msgId = pstParam->msg_id;
   
   int numAct = pstParam->numAct;

   eleActCheck * pstCheckData = pstParam->pstCheckData; 
   int lenRecv = 0;
   msgAckLua ctlMsgRecv;
   int updateRet = 0;
   //printf("in thread_recv_msg, msgId is %d\n",msgId); 
   while(!g_flag_exit_thread)
   {
        lenRecv = msgrcv(msgId, &ctlMsgRecv, sizeof(recvDataEleCtl), QUEUE_MSG_TYPE_LUA, IPC_NOWAIT);
        if(lenRecv>0)
        {
            printf("recv lua queue message\n");
            //pCan->WriteCanPort(&stMsgFrame.frame);
            //printf("opcode[%d],ele_num[%d]\n",ctlMsg.ctlFrame.opcode,ctlMsg.ctlFrame.ele_index);
            updateRet = update(&ctlMsgRecv.eleStatus,pstCheckData);

            if(updateRet)
            {
                break;
            }
        }
       usleep(100);
   }

}

void * thread_recv_msg_new(void * param)
{
   lua_thread_param * pstParam =  (lua_thread_param *)param;

   if(pstParam==NULL)
   {
      return NULL;
   }

   int msgId = pstParam->msg_id;
   
   //int numAct = pstParam->numAct;

   //eleActCheck * pstCheckData = pstParam->pstCheckData; 
   int lenRecv = 0;
   msgAckLua ctlMsgRecv;
   int updateRet = 0;
   //printf("in thread_recv_msg_new, msgId is %d,param msg id is %d\n",msgId,pstParam->msg_id); 
   
   while(!g_flag_exit_thread)
   {
        lenRecv = msgrcv(msgId, &ctlMsgRecv, sizeof(recvDataEleCtl), QUEUE_MSG_TYPE_LUA, IPC_NOWAIT);
        if(lenRecv>0)
        {
            printf("recv lua queue message\n");
            //pCan->WriteCanPort(&stMsgFrame.frame);
            //printf("opcode[%d],ele_num[%d]\n",ctlMsg.ctlFrame.opcode,ctlMsg.ctlFrame.ele_index);
            updateData(&ctlMsgRecv.eleStatus);
        }
       usleep(100);
   }
   free(pstParam);

   printf("exit thread_recv_msg_new\n");

}

pthread_t g_recvHandl = 0;

int initLuaActMsg(void)
{
    initHashEleStatus();
    g_msg_id_to_lua = -1;
    g_msg_id_to_act = -1;

    key_t key = ftok(msgQueueKeyPath, 0x1234);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
//this msg id is used to send to act
    g_msg_id_to_act = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
    if(g_msg_id_to_act < 0)
    {
        perror("msgget g_msg_id_to_act");
        return -1;
    }
  

    key = ftok(msgLuaQueuePath, keyMsg_LUA);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    //this msg id is used to recv the ack
    g_msg_id_to_lua = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
    if(g_msg_id_to_lua < 0)
    {
        perror("msgget g_msg_id_to_lua");
        return -1;
    } 

    printf("g_msg_id_to_lua is %d\n",g_msg_id_to_lua);   
    pthread_mutex_init(&mutex_hash,NULL);
    pthread_mutex_init(&mutex_checkdata,NULL);
    lua_thread_param *pstThreadParam = (lua_thread_param*)malloc(sizeof(lua_thread_param));
    memset(pstThreadParam,0,sizeof(lua_thread_param));
    pstThreadParam->msg_id = g_msg_id_to_lua;
    g_flag_exit_thread = 0;
    pthread_create(&g_recvHandl,NULL,thread_recv_msg_new,pstThreadParam);
}

int Dp8Droptip(int posLow, int posUp)
{
    move_param arrMoveParam[2];

    //const int SID_DP8_Z = 15;

    memset(arrMoveParam,0,sizeof(move_param)*2);
    arrMoveParam[0].dec_speed = 80000;
    arrMoveParam[0].inc_speed = 80000;
    arrMoveParam[0].speed = 20000;
    arrMoveParam[0].pos = posLow;
    arrMoveParam[0].sid = SID_DP8_DROPTIP;

    int moveRet = uimMoveAct_multi(arrMoveParam, 1, 12000);

    if(!moveRet)
    {
        printf("in Dp8Droptip, move to low pos failed\n");
        return 0;
    }

    memset(arrMoveParam,0,sizeof(move_param)*2);
    arrMoveParam[0].dec_speed = 80000;
    arrMoveParam[0].inc_speed = 80000;
    arrMoveParam[0].speed = 20000;
    arrMoveParam[0].pos = posUp;
    arrMoveParam[0].sid = SID_DP8_DROPTIP;

    moveRet = uimMoveAct_multi(arrMoveParam, 1, 12000);

    return moveRet;
}

int uimMoveAct_multi_relative(move_param * paramIn, int num, int timeOut_ms)
{
  
  msg_ctl_uim msgToAct;

  memset(&msgToAct,0,sizeof(msg_ctl_uim));

  msgToAct.type = QUEUE_MSG_TYPE_UIM;


   char * ptrCheckData = NULL;
   set_check_data(paramIn, num, (void**)&ptrCheckData);

   if(ptrCheckData==NULL)
   {
       printf("set check data failed\n");
       return -2;
   }

   move_param * ptrMoveParam =  paramIn;
   #define LUA_MOVE_RELATIVE 7
   int sendOkFlag = 1;
    for(int i=0;i<num;i++)
    {
        msgToAct.ctlFrame.sid = ptrMoveParam->sid;
        msgToAct.ctlFrame.msgSrc = MSG_FROM_LUA;
        msgToAct.ctlFrame.opcode = LUA_MOVE_RELATIVE;//equals to MOVE_RELATIVE
        if(msgToAct.ctlFrame.sid >=10 && msgToAct.ctlFrame.sid <=60)
        {
            msgToAct.type = QUEUE_MSG_TYPE_UIM;            
            msgToAct.ctlFrame.un_cmd.moveCtl.dec_speed = ptrMoveParam->dec_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.inc_speed = ptrMoveParam->inc_speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.position = ptrMoveParam->pos;
            msgToAct.ctlFrame.un_cmd.moveCtl.speed = ptrMoveParam->speed;
            msgToAct.ctlFrame.un_cmd.moveCtl.dir = ptrMoveParam->dir;

        }
        
        if(msgsnd(g_msg_id_to_act, (void*)&msgToAct, sizeof(ctl_uim), 0) < 0)
        {
            printf("msgsnd failed, when i=%d\n",i);
            perror("msgsnd");
            sendOkFlag = 0;
        }
        ptrMoveParam++;
    }
    int flagSuccess = 0;
    //printf("msgsnd send ok\n");
    if(sendOkFlag==1)
    {
        int count_ms = timeOut_ms;
        
        while(count_ms>0)
        {
            //1,check if the action done
            flagSuccess = checkAllFinished(ptrCheckData);
            if(flagSuccess)
            {
                printf("all ack received\n");
                break;
            }
            //2,check if timeout
            count_ms--;
            if(count_ms<0)
            {
                flagSuccess = 0;
                printf("timeout when waiting ack\n");
                break;
            }
            usleep(1000);
        }
        //printf("waiting ack exit, count_mm:%d\n",count_mm); 

    } 

    if(!flagSuccess)
    {
        refreshStatus(ptrCheckData);//if status is waiting, set it to be timeout
    }
    //printf("ptrCheckData free now\n");  
    pthread_mutex_lock(&mutex_checkdata);
    if(ptrCheckData)
    {
        free(ptrCheckData);
        ptrCheckData = NULL;
    }
    pthread_mutex_unlock(&mutex_checkdata);
    printf("ptrCheckData free finished\n");

  return flagSuccess;
}

int deinitLuaActMsg(void)
{
    g_flag_exit_thread = 1;
    pthread_join(g_recvHandl,NULL);
    freeHashEleStatus(); 
    pthread_mutex_destroy(&mutex_hash);
    pthread_mutex_destroy(&mutex_checkdata);

}
 